package com.pss.common.response;

import cn.hutool.core.lang.Assert;
import com.fasterxml.jackson.annotation.JsonIgnore;

import java.time.LocalDateTime;

public class Response<T> {

    private int code;
    private String message;
    private T data;
    private LocalDateTime lastModifiedTime;
    @JsonIgnore
    private Object[] params;
    private String details;

    public Response() {
        this.code = StatusCode.SUCCESS.getCode();
        this.message = StatusCode.SUCCESS.getDesc();
    }

    public Response(T data, StatusCode statusCode, LocalDateTime lastModifiedTime, Object... params) {
        this.code = StatusCode.SUCCESS.getCode();
        this.message = StatusCode.SUCCESS.getDesc();
        if (statusCode != null) {
            this.code = statusCode.getCode();
            this.message = statusCode.getDesc();
        }

        this.lastModifiedTime = lastModifiedTime;
        this.data = data;
        this.params = params;
    }

    public Response(T data, int code, String msg, LocalDateTime lastModifiedTime, Object... params) {
        this.code = StatusCode.SUCCESS.getCode();
        this.message = StatusCode.SUCCESS.getDesc();
        this.data = data;
        this.code = code;
        this.message = msg;
        this.lastModifiedTime = lastModifiedTime;
        this.params = params;
    }

    public Response(Throwable e, T data) {
        this.code = StatusCode.SUCCESS.getCode();
        this.message = StatusCode.SUCCESS.getDesc();
        this.message = e.getMessage();
        this.code = StatusCode.ERROR.getCode();
    }

    private Response(T data, Builder builder) {
        this.code = StatusCode.SUCCESS.getCode();
        this.message = StatusCode.SUCCESS.getDesc();
        this.code = builder.code;
        this.message = builder.msg;
        this.data = data;
        this.lastModifiedTime = builder.lastModifiedTime;
        this.params = builder.params;
        this.details = builder.details;
    }

    private Response(Builder builder) {
        this((T) null, (Builder) builder);
    }

    public static Response success() {
        return body(StatusCode.SUCCESS).build();
    }

    public static Response success(LocalDateTime lastModifiedTime) {
        return body(StatusCode.SUCCESS).lastModifiedTime(lastModifiedTime).build();
    }

    public static <T> Response<T> success(T data) {
        return body(StatusCode.SUCCESS).build(data);
    }

    public static <T> Response<T> success(T data, LocalDateTime lastModifiedTime) {
        return body().lastModifiedTime(lastModifiedTime).build(data);
    }

    public static <T> Response success(T data, String msg) {
        return body().code(StatusCode.SUCCESS.getCode()).msg(msg).build(data);
    }

    public static <T> Response<T> success(T data, String msg, LocalDateTime lastModifiedTime) {
        return body().code(StatusCode.SUCCESS.getCode()).msg(msg).lastModifiedTime(lastModifiedTime).build(data);
    }

    public static <T> Response<T> success(T data, int code, String msg) {
        return body().code(code).msg(msg).build(data);
    }

    public static <T> Response<T> success(T data, int code, String msg, LocalDateTime lastModifiedTime) {
        return body().code(code).msg(msg).lastModifiedTime(lastModifiedTime).build(data);
    }

    public static <T> Response<T> success(T data, StatusCode statusCode) {
        return body(statusCode).build(data);
    }

    public static <T> Response<T> success(T data, StatusCode statusCode, LocalDateTime lastModifiedTime) {
        return body(statusCode).lastModifiedTime(lastModifiedTime).build(data);
    }

    public static <T> Response<T> error() {
        return body(StatusCode.ERROR).build();
    }

    public static <T> Response<T> error(StatusCode statusCode) {
        return body(statusCode).build();
    }

    public static <T> Response<T> error(StatusCode statusCode, Object... params) {
        return body().statusCode(statusCode, params).build();
    }

    public static <T> Response<T> error(String msg) {
        return body().code(StatusCode.ERROR.getCode()).msg(msg).build();
    }

    public static <T> Response<T> error(int code, String msg) {
        return body().code(code).msg(msg).build();
    }

    public static <T> Response<T> error(T data, StatusCode statusCode) {
        return body(statusCode).build(data);
    }

    public static <T> Response<T> error(T data, StatusCode statusCode, LocalDateTime lastModifiedTime) {
        return body(statusCode).lastModifiedTime(lastModifiedTime).build(data);
    }

    public static <T> Response<T> error(T data, String msg) {
        return body().code(StatusCode.ERROR.getCode()).msg(msg).build(data);
    }

    public static <T> Response<T> error(T data, String msg, LocalDateTime lastModifiedTime) {
        return body().code(StatusCode.ERROR.getCode()).msg(msg).lastModifiedTime(lastModifiedTime).build(data);
    }

    public static <T> Response<T> error(T data, int code, String msg) {
        return body().code(code).msg(msg).build(data);
    }

    public static <T> Response<T> error(T data, int code, String msg, String details) {
        return body().code(code).msg(msg).details(details).build(data);
    }

    public static <T> Response<T> error(T data, int code, String msg, LocalDateTime lastModifiedTime) {
        return body().code(code).msg(msg).lastModifiedTime(lastModifiedTime).build(data);
    }

    public int getCode() {
        return this.code;
    }

    public String getMessage() {
        return this.message;
    }

    public T getData() {
        return this.data;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public void setData(T data) {
        this.data = data;
    }

    public Object[] getParams() {
        return this.params;
    }

    public void setParams(Object... params) {
        this.params = params;
    }

    public LocalDateTime getLastModifiedTime() {
        return this.lastModifiedTime;
    }

    public void setLastModifiedTime(LocalDateTime lastModifiedTime) {
        this.lastModifiedTime = lastModifiedTime;
    }

    public boolean isSuccess() {
        return this.code == 0;
    }

    public String getDetails() {
        return this.details;
    }

    public void setDetails(String details) {
        this.details = details;
    }

    public static Builder body() {
        return new Builder();
    }

    public static Builder body(StatusCode statusCode) {
        return new Builder(statusCode);
    }

    public static final class Builder {
        private int code;
        private String msg;
        private LocalDateTime lastModifiedTime;
        private Object[] params;
        private String details;

        Builder() {
            this.code = StatusCode.SUCCESS.getCode();
            this.msg = StatusCode.SUCCESS.getDesc();
        }

        Builder(StatusCode statusCode) {
            this.code = StatusCode.SUCCESS.getCode();
            this.msg = StatusCode.SUCCESS.getDesc();
            Assert.notNull(statusCode, "statusCode can't null", new Object[0]);
            this.code = statusCode.getCode();
            this.msg = statusCode.getDesc();
        }

        public Builder statusCode(StatusCode statusCode) {
            Assert.notNull(statusCode, "statusCode can't null", new Object[0]);
            this.code = statusCode.getCode();
            this.msg = statusCode.getDesc();
            return this;
        }

        public Builder statusCode(StatusCode statusCode, Object[] params) {
            Assert.notNull(statusCode, "statusCode can't null", new Object[0]);
            this.code = statusCode.getCode();
            this.msg = statusCode.getDesc();
            this.params = params;
            return this;
        }

        public Builder code(int code) {
            this.code = code;
            return this;
        }

        public Builder msg(String msg) {
            this.msg = msg;
            return this;
        }

        public Builder params(Object[] params) {
            this.params = params;
            return this;
        }

        public Builder msg(String msg, Object[] params) {
            this.msg = msg;
            this.params = params;
            return this;
        }

        public Builder details(String details) {
            this.details = details;
            return this;
        }

        public Builder lastModifiedTime(LocalDateTime lastModifiedTime) {
            this.lastModifiedTime = lastModifiedTime;
            return this;
        }

        public <T> Response<T> build() {
            return new Response(this);
        }

        public <T> Response<T> build(T data) {
            return new Response(data, this);
        }
    }
}
